package com.omt.tarjimdinek.conversation;

import static com.omt.tarjimdinek.conversation.ConversationHolder.getCurrentConversation;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

/**
 * Beans in the conversation scope reside in a {@link Conversation conversation}'s {@link ConversationContext}.
 * They are 'visible' only when the conversation is bound to the current Thread of execution and their 
 * hosting ConversationContext is on top of the conversation's contextes stack.
 * 
 * Such a design decision allows a conversation to have 2 'conversation scoped' beans with 
 * the same name (they just have to reside in 2 different ConversationContext).
 * This prevents bean name clash in complex navigation scenario within the same conversation.
 */
public class ConversationScope implements Scope {

    @Override
    public String getConversationId() {
        return getCurrentConversation().getId();
    }

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Conversation currentConversation = getCurrentConversation();
        Object bean = currentConversation.getBean(name);

        if (bean == null) {
            bean = objectFactory.getObject();
            currentConversation.addBean(name, bean);
        }

        return bean;
    }

    @Override
    public Object remove(String name) {
        throw new UnsupportedOperationException("remove is done during conversation.end");
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // no ops
    }

    @Override
    public Object resolveContextualObject(String key) {
        return getCurrentConversation().getVar(key);
    }
}